#pragma once
#include "buffer.hpp"
#include <mutex>
#include <condition_variable>
#include <atomic> 
#include <thread>
#include <functional>


namespace CH
{
	//异步工作器
	class AsynchWork
	{
		
	public:
		using prt=std::shared_ptr<AsynchWork>;
		//该函数是我们用户，传进来处理缓冲区数据的方法函数
		using Functor=std::function<void(Buffer&)>;
		AsynchWork(const Functor& callback)
			:_callback(callback),_stop(false),_thread(&AsynchWork::ThreadEntry,this)
		{}

		//停止运行异步工作器
		void Stop()
		{
			_stop=true;     				//退出标志
			_consumer_cond.notify_all();    //唤醒消费者所有的线程
			_thread.join();					//阻塞线程，等待线程的工作全部处理完毕，才会执行后序代码
		}

		//将数据放入异步工作器的生产缓冲区中
		void push(const char* data,size_t len)
		{
			//加锁，在函数结束时自动释放
			std::unique_lock<std::mutex> lock(_mutex);
			//[&]:捕捉列表，可以在函数体内，访问外部变量或修改外部变量
			//_produce_cond.wait():根据后面的表达式，为真则进入下一步，为假则释放锁并且阻塞，等待被唤醒
			_produce_cond.wait(lock,[&](){return len<=_produce_buffer.writeAbleSize();});
			//将数据放入生产缓冲区中
			_produce_buffer.push(data,len);
			//唤醒消费者对缓冲区中的数据进行处理
			_consumer_cond.notify_one();
		}

		//线程的入口函数，默认类中的函数都具有this指针，所以在将该函数设为入口函数时，需要传入this指针
		//对缓冲区中的数据进行处理，处理完后初始化缓冲区，交换缓冲区
		void ThreadEntry()
		{
			while(true)
			{
				//给锁添加一个生命周期，当缓冲区交换完后，就解锁
				{
					std::unique_lock<std::mutex> lock(_mutex);
					//当有数据进来是会调用push函数，则会唤醒消费者,判断生产缓冲区中是否有数据，没有则阻塞等待
					_consumer_cond.wait(lock,[&](){return !_produce_buffer.bufferEmpty()||_stop;});
					if(_stop&&_produce_buffer.bufferEmpty()) break;
					//交换缓冲区
					_consumer_buffer.bufferSwap(_produce_buffer);
					//唤醒生产者
					_produce_cond.notify_one();
				}
				//走到这里，消费者缓冲区中有数据，则对，消费者缓冲区中的数据进行处理
				_callback(_consumer_buffer);
				//处理完数据后，则对缓冲区进行初始化
				_consumer_buffer.bufferReset();
			}
		}

	private:
		std::atomic<bool> _stop;   				  //控制异步工作器是关闭，还是打开
		std::mutex _mutex;                        //d定义锁，保证线程安全
		Buffer _produce_buffer;					  //生产者缓冲区
		Buffer _consumer_buffer;				  //消费者缓冲区
		std::condition_variable _produce_cond;	  //生产者条件变量
		std::condition_variable _consumer_cond;	  //消费者条件变量
		std::thread _thread;                      //创建线程
		Functor _callback;						  //定义回调函数
	};
}
